<template>
  <el-form ref="spuForm" :model="spuInfo" :rules="spuFormRules" label-width="100px">
    <el-form-item label="SPU名称" prop="spuName">
      <el-input v-model="spuInfo.spuName" placeholder="请输入SPU名称"></el-input>
    </el-form-item>
    <el-form-item label="SPU品牌" prop="tmId">
      <el-select v-model="spuInfo.tmId" placeholder="请选择">
        <el-option :label="tm.tmName" v-for="tm in trademarkList" :key="tm.id" :value="tm.id" />
      </el-select>
    </el-form-item>
    <el-form-item label="SPU描述" prop="description">
      <el-input v-model="spuInfo.description" :rows="4" type="textarea" />
    </el-form-item>
    <el-form-item label="SPU图片" prop="spuImageList">
      <el-upload v-model:file-list="spuInfo.spuImageList" :action="`${BASE_URL}/admin/product/upload`" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
        <el-icon>
          <Plus />
        </el-icon>
      </el-upload>

      <el-dialog v-model="dialogVisible">
        <img w-full :src="dialogImageUrl" alt="Preview Image" />
      </el-dialog>
    </el-form-item>
    <el-form-item label="销售属性" prop="spuSaleAttrList">
      <el-select v-model="spuInfo.spuSaleAttr" :placeholder="`还有${filterSpuSaleAttrList.length}项未选择`">
        <el-option :label="saleAttr.name" v-for="saleAttr in filterSpuSaleAttrList" :value="saleAttr.name" :key="saleAttr.id" />
      </el-select>
      <el-button type="primary" :icon="Plus" style="margin-left:6px;" :disabled="!spuInfo.spuSaleAttr" @click="addSpuSaleAttr">添加销售属性</el-button>
      <el-table :data="spuInfo.spuSaleAttrList" border style="margin:16px 0;">
        <el-table-column label="序号" type="index" align="center" width="80"></el-table-column>
        <el-table-column label="属性名" prop="saleAttrName" align="center" width="160"></el-table-column>
        <el-table-column label="属性值名称列表">
          <template v-slot="{row}">
            <el-tag v-for="saleAttrValue in row.spuSaleAttrValueList" :key="saleAttrValue.saleAttrValueName " style="margin-right:4px;" class="mx-1" closable :disable-transitions="false" @close="handleClose(row,saleAttrValue)">
              {{ saleAttrValue.saleAttrValueName }}
            </el-tag>
            <el-input style="width:60px;" v-if="row.inputVisible" ref="InputRef" v-model="inputValue" class="ml-1 w-20" size="small" @keyup.enter="handleInputConfirm(row)" @blur="handleInputConfirm(row)" />
            <el-button v-else class="button-new-tag ml-1" size="small" @click="showInput(row)">
              + New Tag
            </el-button>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template v-slot="{row,$index}">
            <el-popconfirm title="您真的要删除此属性吗?" @confirm="confirmEvent($index)" @cancel="cancelEvent">
              <template #reference>
                <el-button title="删除属性" type="danger" :icon="Delete" size="small"></el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>

    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(spuForm)">保存</el-button>
      <el-button @click="emits('setShowStatus',ShowStatus.SPU_LIST)">取消</el-button>
    </el-form-item>

  </el-form>
</template>

<script lang="ts">
export default {
  name: 'SpuForm'
};
</script>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, nextTick } from 'vue';
import { Plus, Delete } from '@element-plus/icons-vue';
import { ElMessage, ElInput } from 'element-plus';
import type { UploadProps, UploadUserFile, FormInstance, FormRules } from 'element-plus';
import { reqGetAllBaseSaleAttrListData, reqGetAllTrademarkListData, reqGetSpuImageListData, reqGetSpuSaleAttrListData, reqSaveSpuInfo, reqUpdateSpuInfo } from '@/api/product/spu';
import { ShowStatus } from '../types';
import { useCategoryListStore } from '@/stores/categoryList';
// 获取对应的store对象
const categoryStore = useCategoryListStore();
const emits = defineEmits(['setShowStatus']);

const props = defineProps(['currentSpuInfo']);
const fileList = ref<UploadUserFile[]>([]);

const dialogImageUrl = ref('');
const dialogVisible = ref(false);

// 定义两个变量 分别是trademarkList  baseSaleAttrList
const trademarkList = ref([]);
const baseSaleAttrList = ref([]);

const BASE_URL = import.meta.env.VITE_API_URL;

// 销售属性中的动态编辑标签
const inputValue = ref('');

const inputVisible = ref(false);
const InputRef = ref<InstanceType<typeof ElInput>>();
const spuForm = ref<FormInstance>();
// 定义一个spuInfo对象 来收集对应的数据
const spuInfo = reactive({
  spuName: '', // SPU名称
  description: '', // SPU描述
  tmId: '', // SPU品牌
  category3Id: 0,
  spuImageList: [], // 图片列表项
  spuSaleAttrList: [], // 属性名列表项
  spuSaleAttr: '', // 额外添加的一个属性
  ...props.currentSpuInfo
});

// 0. spuInfo的数据校验
const spuFormRules = reactive<FormRules>({
  spuName: [
    { required: true, message: '请输入SpuName', trigger: 'blur' },
    { min: 1, max: 10, message: '长度应该在1 to 10之间', trigger: 'blur' }
  ],
  description: [{ required: true, message: '请输入Spu描述', trigger: 'blur' }],
  tmId: [{ required: true, message: '请输入Spu品牌', trigger: 'change' }],
  spuImageList: [
    {
      type: 'array',
      required: true,
      message: '请至少上传一张图片',
      trigger: 'change'
    }
  ],
  spuSaleAttrList: [
    {
      type: 'array',
      required: true,
      message: '请选择销售属性',
      trigger: 'change'
    }
  ]
});

// 1. 当页面组件挂载完毕之后 一次性发送两个请求 分别获取品牌列表和销售属性
onMounted(async () => {
  // const result1 = await reqGetAllTrademarkListData()
  // const result2 = await reqGetAllBaseSaleAttrListData()

  try {
    // Promise.all 如果都成功最终结果才是成功 如果有一个失败那最终就是失败
    // 当成功时 返回来的数据 严格按照我们书写的顺序来处理

    // 1.1 获取id
    const { id } = spuInfo;
    // 1.2 定义一个数组 来存储接口函数 其实就是用来存储Promise实例对象
    let promises = [reqGetAllTrademarkListData(), reqGetAllBaseSaleAttrListData()];
    // 1.3 判断是不是编辑操作
    if (id) {
      promises = promises.concat([reqGetSpuImageListData(id), reqGetSpuSaleAttrListData(id)]);
    }
    // 1.4 一次性发送2次或4次请求
    const [responseTrademarkList, responseBaseAttrList, responseSpuImageList, responseSpuSaleAttrList] = await Promise.all(promises);
    // console.log('res',responseTrademarkList,responseBaseAttrList)
    // console.log('rr',responseSpuImageList,responseSpuSaleAttrList)
    trademarkList.value = responseTrademarkList;
    baseSaleAttrList.value = responseBaseAttrList;

    // 1.5 根据响应回来的数据进行赋值
    if (responseSpuImageList && responseSpuSaleAttrList) {
      // spuInfo.spuImageList = responseSpuImageList;
      spuInfo.spuImageList = responseSpuImageList.map(item => {
        return {
          ...item,
          name: item.imgName,
          url:item.imgUrl
        }
      });
      // fileList.value = responseSpuImageList.map(item => {
      //   return {
      //     // ...item,
      //     name: item.imgName,
      //     url: item.imgUrl
      //   };
      // });
      spuInfo.spuSaleAttrList = responseSpuSaleAttrList;
    }
  } catch (error) {
    ElMessage.error('发送请求获取品牌或是销售属性失败了...');
  }
});

// 2. 图片上传成功之后会触发的函数
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile, uploadFiles) => {
  // console.log('111',response,uploadFile,uploadFiles)

  spuInfo.spuImageList = uploadFiles
  // 当前先上传成功一张图片就收集一张图片的链接及名称
  // spuInfo.spuImageList.push({
  //   imgName: uploadFile.name,
  //   imgUrl: response.data
  // });

  // 上传成功之后， 可以手动清除校验提示
  spuForm.value?.clearValidate(['spuImageList']);
};

// 3. 图片上传之前要校验图片格式及大小
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
  const imgTypes = ['image/jpeg', 'image/gif', 'image/png'];
  // if (rawFile.type !== 'image/jpeg') {
  if (!imgTypes.includes(rawFile.type)) {
    ElMessage.error('图片格式不正确,应该是jpg/jpeg/gif/png');
    return false;
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('图片大小应该是在2M以内,请重新选择...');
    return false;
  }
  return true;
};

// 4. 删除上传的图片数据 在收集到的数据中删除掉不想上传的图片
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
  console.log('uu', uploadFile, uploadFiles);
  // spuInfo.spuImageList = uploadFiles // 如果这么写的话，在最后真正添加spu的时候需要再次处理一下，因为服务器端要的参数只有imgName imgUrl

  // spuInfo.spuImageList = uploadFiles.map(item => {
  //   return {
  //     imgName: item.name,
  //     // imgUrl: item.response.data // 这个写法只适用于添加时的操作
  //     imgUrl: item.response ? item.response.data : item.url
  //   };
  // });

  spuInfo.spuImageList = uploadFiles
};

// 5. 实现图片预览
const handlePictureCardPreview: UploadProps['onPreview'] = uploadFile => {
  dialogImageUrl.value = uploadFile.url!;
  dialogVisible.value = true;
};

// 6. 实现销售属性添加功能
const addSpuSaleAttr = () => {
  // 6.1 添加新的销售属性时 要判断一下之前的销售属性值是否为空 如果为空不要添加新的销售属性
  const spuSaleAttrList = spuInfo.spuSaleAttrList;
  if (spuSaleAttrList.length && spuSaleAttrList.some(item => item.spuSaleAttrValueList.length === 0)) {
    ElMessage.warning('请添加对应属性的属性值...');
    return;
  }
  const id = baseSaleAttrList.value.find(item => item.name === spuInfo.spuSaleAttr).id;
  spuInfo.spuSaleAttrList.push({
    baseSaleAttrId: id,
    inputVisible: false,
    // saleAttrName: '', // 属性的名字
    saleAttrName: spuInfo.spuSaleAttr,
    spuSaleAttrValueList: [] // 属性值数组 是用来收集具体的属性值的
  });

  // 清空下拉菜单中的显示项
  spuInfo.spuSaleAttr = '';
};

// 7. 实现销售属性添加到下面的表格后的删除效果
const filterSpuSaleAttrList = computed(() => {
  // 从baseSaleAttrList原始属性数组中过滤出,还没有添加到表格数组中的选项
  return baseSaleAttrList.value.filter(item => {
    return !spuInfo.spuSaleAttrList.find(spuSaleAttr => spuSaleAttr.saleAttrName === item.name);
  });
});

// 8. 删除属性
const confirmEvent = (index: number) => {
  spuInfo.spuSaleAttrList.splice(index, 1);
};
// 9. 取消删除属性
const cancelEvent = () => {
  ElMessage({
    type: 'info',
    message: '取消删除属性了...'
  });
};

// 10. 删除销售属性中的属性值
// const handleClose = (row,index) => {
const handleClose = (row, saleAttrValue) => {
  // dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1)
  // row.spuSaleAttrValueList.splice(index, 1)

  row.spuSaleAttrValueList.splice(row.spuSaleAttrValueList.indexOf(saleAttrValue), 1);
};

// 11. 单击属性值按钮 实现一个样式切换
const showInput = row => {
  // inputVisible.value = true
  row.inputVisible = true;
  nextTick(() => {
    // 当前属性的属性值输入框获取焦点
    // TS中的非空断言操作符（non-null assertion operator）
    // 这个符号表示对象后面的属性一定不是null或undefined
    InputRef.value!.input!.focus();
  });
};

// 12. 添加新的销售属性值
const handleInputConfirm = saleAttr => {
  if (inputValue.value) {
    // 12.1 先精简一下对象中的属性 赋值给一个变量
    const spuSaleAttrValueList = saleAttr.spuSaleAttrValueList;
    if (spuSaleAttrValueList.length && spuSaleAttrValueList.some(item => item.saleAttrValueName === inputValue.value)) {
      ElMessage.warning('属性值不能重复,请更换一个...');
      saleAttr.inputVisible = false;
      inputValue.value = '';
      return;
    }
    // 12.2 获取销售属性对应的id
    // const id = baseSaleAttrList.value.find(item=>item.name ===saleAttr.saleAttrName).id
    saleAttr.spuSaleAttrValueList.push({
      baseSaleAttrId: saleAttr.baseSaleAttrId,
      isChecked: 0,
      saleAttrName: saleAttr.saleAttrName,
      saleAttrValueName: inputValue.value
    });
  }
  // inputVisible.value = false
  saleAttr.inputVisible = false;
  inputValue.value = '';
};

// 13. 添加SpuInfo
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      // 13.1 对于销售属性中的属性值 提前之前一定要校验一下
      const spuSaleAttrList = spuInfo.spuSaleAttrList;
      if (spuSaleAttrList.length && spuSaleAttrList.some(item => item.spuSaleAttrValueList.length === 0)) {
        ElMessage.warning('有属性的属性值为空,请添加...');
        return;
      }

      spuInfo.category3Id = categoryStore.category3Id as number;

      spuInfo.spuImageList = spuInfo.spuImageList.map((item:any) => {
        return {
          imgName: item.name,
          imgUrl:item.response?item.response.data : item.url
        }
      })

      if (spuInfo.id) {
        await reqUpdateSpuInfo(spuInfo);
      } else {
        await reqSaveSpuInfo(spuInfo);
      }

      ElMessage.success('操作spuInfo成功...');

      // 要跳转到spuList页面
      emits('setShowStatus', ShowStatus.SPU_LIST);
    } else {
      console.log('error submit!', fields);
    }
  });
};
</script>

<style>
</style>